package com.lpit.mysql;


import lombok.Data;
import org.aspectj.lang.annotation.Aspect;
import org.omg.CORBA.UserException;
import org.springframework.aop.Advisor;
import org.springframework.aop.aspectj.AspectJExpressionPointcut;
import org.springframework.aop.support.DefaultPointcutAdvisor;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.context.annotation.PropertySource;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.transaction.interceptor.DefaultTransactionAttribute;
import org.springframework.transaction.interceptor.NameMatchTransactionAttributeSource;
import org.springframework.transaction.interceptor.TransactionInterceptor;

import javax.sql.DataSource;

@Data
@Aspect
@Configuration
@EnableAspectJAutoProxy
@EnableTransactionManagement
@ConfigurationProperties(prefix = "mysql.dev.tx")
@PropertySource("classpath:mysql-dev-jdbc.properties")//地址
public class TransactionConfig {

    /*切入点表达式字符串，指定那些包下的那些类使用事务，从配置文章中获取*/
    private String txScanPackage;

    /**
     * 事务管理器，注入数据源
     *
     * @param dataSource
     * @return
     */
    @Bean("mysqlTransactionManager")
    public DataSourceTransactionManager mysqlTransactionManager(@Qualifier("mysqlDevDataSource") DataSource dataSource) {
        DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager();
        dataSourceTransactionManager.setDataSource(dataSource);
        return dataSourceTransactionManager;
    }

    /**
     * 事务拦截器
     *
     * @param dataSourceTransactionManager
     * @return
     */
    @Bean("mysqlTxAdvice")
    public TransactionInterceptor mysqlTxAdvice(@Qualifier("mysqlTransactionManager") DataSourceTransactionManager dataSourceTransactionManager) {
        /*配置查询的事务属性*/
        DefaultTransactionAttribute query = new DefaultTransactionAttribute();
        /*配置是否只读*/
        query.setReadOnly(true);
        /*设置事务传播行为（支持当前事务，假设当前没有事务。就新建一个事务）*/
        query.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);

        /*配置其他的事务属性并设置事务传播行为，也可以像上面一样用setPropagationBehavior方法设置*/
        DefaultTransactionAttribute defaul = new DefaultTransactionAttribute(TransactionDefinition.PROPAGATION_REQUIRED);

        //声明一个通过方法名字配置事务属性的对象
        NameMatchTransactionAttributeSource nameMatchTransactionAttributeSource = new NameMatchTransactionAttributeSource();
        //通过方法名称设置业务方法事务属性，下面根据方法名称设置也可以用setNameMap方法设置\

        /*只读事务*/
        nameMatchTransactionAttributeSource.addTransactionalMethod("select*", query);
        nameMatchTransactionAttributeSource.addTransactionalMethod("get*", query);
        nameMatchTransactionAttributeSource.addTransactionalMethod("find*", query);
        /*修改事务*/
        nameMatchTransactionAttributeSource.addTransactionalMethod("delete*", defaul);
        nameMatchTransactionAttributeSource.addTransactionalMethod("add*", defaul);
        nameMatchTransactionAttributeSource.addTransactionalMethod("save*", defaul);
        nameMatchTransactionAttributeSource.addTransactionalMethod("update*", defaul);
        nameMatchTransactionAttributeSource.addTransactionalMethod("insert*", defaul);
        nameMatchTransactionAttributeSource.addTransactionalMethod("del*", defaul);

        //返回一个事务拦截器
        return new TransactionInterceptor(dataSourceTransactionManager, nameMatchTransactionAttributeSource);

    }

    /**
     * 适配器方法
     *
     * @param transactionInterceptor
     * @return
     */
    @Bean
    public Advisor mysqlAdvisor(@Qualifier("mysqlTxAdvice") TransactionInterceptor transactionInterceptor) {
        /*配置事务切点表达式*/
        AspectJExpressionPointcut aspectJExpressionPointcut = new AspectJExpressionPointcut();
        aspectJExpressionPointcut.setExpression(this.txScanPackage);
        /*增强事务，管理事务切点跟属性*/
        return new DefaultPointcutAdvisor(aspectJExpressionPointcut, transactionInterceptor);
    }
}
